#ifndef DEFINITION_H
#define DEFINITION_H

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <errno.h>
#include <pthread.h>

#define MAXBUFFSIZE 10240

#define S_REQUEST 0x60
#define M_REQUEST 0x61
#define S_RESPONSE 0x10
#define M_RESPONSE 0x11
#define CONNECT 0x40

//#define BACKUP_LEADER 1
//#define BACKUP_SLAVE  1

typedef struct _TCPheader {
    uint8_t type; // 1
	uint8_t src_ip;  // 1 +1
	uint16_t port; // 2 +2
	uint16_t num_msg; // 2 +4
	uint16_t len_msg; // 2 +6
    //uint32_t ack; // 4 +8
} TCPheader; // 12  [12]

typedef struct {
	uint8_t type; // 1
	uint8_t src_ip;  // 4 +1
	uint16_t port; // 2 +5
	uint16_t num_msg; // 2 +7
	uint16_t len_msg; // 2 +9
    //uint32_t ack; // 4 +11
} INNER_H; // 15

typedef enum {
	HDTYPE_SIN_REQUEST = 0x60,
	HDTYPE_MUL_REQUEST = 0x61,
	HDTYPE_SIN_RESPONSE = 0x10,
	HDTYPE_MUL_RESPONSE = 0x11,
	HDTYPE_CONNECT = 0x40, // CONNECT
	HDTYPE_CLIENT_NFV_CONN = 0x41, // CONNECT from client/NFV
	HDTYPE_LEADER_CONN = 0x42 // CONNECT from leader
} request_response_header_type;

typedef struct __attribute__ ((__packed__)) {
  uint8_t magic;
  uint8_t opcode;
  uint16_t key_len;

  uint8_t extra_len;
  uint8_t data_type;
  union {
   uint16_t vbucket; // request use
   uint16_t status;  // response use
  };

  uint32_t body_len;
  union {
      struct {
          uint16_t src_ip;
          uint16_t src_port;
      };
      uint32_t opaque;
  };
  uint64_t cas;

} binary_header_t;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
} binary_get_req_header;

typedef struct __attribute__ ((__packed__)) {
    binary_header_t header;
    struct {
        // Used for set only.
        uint32_t flags;
        uint32_t expiration;
    } extras;
} binary_set_req_header;

typedef enum {
  CMD_GET   =  0x00,
  CMD_BGET  =  0x40,
  CMD_BGETQ =  0x41,
  CMD_MGET  =  0x42, //<== use this
  CMD_GETQ  =  0x09,
  CMD_GETK  =  0x0c,
  CMD_GETKQ =  0x0d,
  CMD_SET   =  0x01,
  CMD_SASL  =  0x21,
  CMD_NOOP  =  0x0a

} protocol_binary_command;


int
format_edittype(TCPheader *header);

int
create_tcp_inner_header(char *dst_buf,
						uint8_t type, uint8_t src_ip, uint16_t port,
						uint16_t num_msg, uint16_t len_msg, uint32_t ack);

int
create_sample_fixpacket(int pkt_num, char *dst_buf, int len_total);

int compose_binary_get(char *request, char *key, int cmd, int ip_rank, int port);
int compose_binary_set(char *request, char *key, char *value, int cmd, int ip_rand, int port);

#endif // DEFINITION_H
